﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UtilZ.Dotnet.Ex.Base;

namespace UtilZ.Dotnet.Ex.Communication.Net.Web
{
    internal partial class ApiMethod
    {
        /// <summary>
        /// 序列化器
        /// </summary>
        private readonly IWebSerializer _serializer;
        private readonly string _routUrl;
        private readonly string _templateUrl = string.Empty;

        /// <summary>
        /// 模板参数api方法固定的url前缀(有利于提升效率)
        /// </summary>
        private readonly string _tempParaApiFixUrlPrefix;



        private readonly HttpMethodAbsAttribute _methodAttribute;
        private readonly object _obj = null;
        private readonly Delegate _mapDelegatede = null;
        private readonly MethodInfo _methodInfo;
        private readonly string _routTemplate;
        private readonly ApiMethodTypes _apiMethodType;
        private readonly ApiTemplatePara _urlTemplateApiTemplatePara = null;
        private readonly ApiTemplatePara _queryStringTemplateApiTemplatePara = null;
        private readonly ReadOnlyCollection<ApiParameterInfo> _apiParameterInfos = null;
        private readonly ApiParameterInfo _apiBodyParameterInfo = null;
        private readonly ApiParameterInfo _httpInfoParameterInfo = null;


        #region 属性
        /// <summary>
        /// http请求方法名
        /// </summary>
        public string Method
        {
            get { return this._methodAttribute.Method; }
        }

        /// <summary>
        /// api方法
        /// </summary>
        public MethodInfo MethodInfo
        {
            get { return _methodInfo; }
        }

        /// <summary>
        /// http路由地址
        /// </summary>
        public string RoutUrl
        {
            get
            {
                return this._routUrl;
            }
        }

        /// <summary>
        /// 获取模板url
        /// </summary>
        public string TemplateUrl
        {
            get { return _templateUrl; }
        }

        /// <summary>
        /// api方法类型
        /// </summary>
        public ApiMethodTypes ApiMethodType
        {
            get { return _apiMethodType; }
        }

        /// <summary>
        /// 获取url模板段集合
        /// </summary>
        public ApiTemplatePara UrlTemplateApiTemplatePara
        {
            get { return _urlTemplateApiTemplatePara; }
        }

        /// <summary>
        /// 获取queryString模板段集合
        /// </summary>
        public ApiTemplatePara QueryStringTemplateApiTemplatePara
        {
            get { return _queryStringTemplateApiTemplatePara; }
        }
        #endregion


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serializer">序列化器</param>
        /// <param name="routTemplate">基准地址</param>
        /// <param name="obj">api所属对象</param>
        /// <param name="methodInfo">api方法信息</param>
        /// <param name="methodAttribute">方法特性</param>
        public ApiMethod(IWebSerializer serializer, string routTemplate, object obj, MethodInfo methodInfo, HttpMethodAbsAttribute methodAttribute)
            : this(serializer, routTemplate, methodInfo, methodAttribute)
        {
            this._obj = obj;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serializer">序列化器</param>
        /// <param name="routTemplate">基准地址</param>
        /// <param name="mapDelegate">委托</param>
        /// <param name="methodAttribute">方法特性</param>
        public ApiMethod(IWebSerializer serializer, string routTemplate, Delegate mapDelegate, HttpMethodAbsAttribute methodAttribute)
            : this(serializer, routTemplate, mapDelegate.Method, methodAttribute)
        {
            this._mapDelegatede = mapDelegate;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serializer">序列化器</param>
        /// <param name="routTemplate">基准地址</param>
        /// <param name="dynamicApi">回调api实例</param>
        /// <param name="methodInfo">api方法信息</param>
        /// <param name="methodAttribute">方法特性</param>
        public ApiMethod(IWebSerializer serializer, string routTemplate, IDynamicApi dynamicApi, MethodInfo methodInfo, HttpMethodAbsAttribute methodAttribute)
            : this(serializer, routTemplate, methodInfo, methodAttribute)
        {
            this._obj = dynamicApi;
        }



        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="serializer">序列化器</param>
        /// <param name="routTemplate">基准地址</param>
        /// <param name="methodInfo">api方法信息</param>
        /// <param name="methodAttribute">方法特性</param>
        private ApiMethod(IWebSerializer serializer, string routTemplate, MethodInfo methodInfo, HttpMethodAbsAttribute methodAttribute)
        {
            this._serializer = serializer;

            if (routTemplate.Length > 0 && routTemplate.First() != Path.AltDirectorySeparatorChar)
            {
                routTemplate = Path.AltDirectorySeparatorChar + routTemplate;
            }

            this._routTemplate = routTemplate;
            this._methodAttribute = methodAttribute;

            this._methodInfo = methodInfo;
            this._apiParameterInfos = this.GetApiMethodParameterInfo(methodInfo);
            this._apiBodyParameterInfo = this._apiParameterInfos.FirstOrDefault(p =>
            {
                return p.TemplateParameterType == ApiParameterValueSourceTypes.FromBody;
            });
            this._httpInfoParameterInfo = this._apiParameterInfos.FirstOrDefault(p =>
            {
                return p.TemplateParameterType == ApiParameterValueSourceTypes.ActionContext;
            });

            //TestGetApiMethodTypeByTemplate();
            this._apiMethodType = this.GetApiMethodTypeByTemplate(methodAttribute.Template, this._apiParameterInfos);


            this.UpdateTemplate(methodInfo, methodAttribute, this._apiParameterInfos);

            string routUrl = this.GenerateRoutUrl(this._apiMethodType, methodInfo, methodAttribute, this._apiParameterInfos,
                out this._urlTemplateApiTemplatePara, out this._queryStringTemplateApiTemplatePara);
            string templateUrl;

            if (string.IsNullOrWhiteSpace(routUrl))
            {
                routUrl = routTemplate;
                templateUrl = routTemplate;
            }
            else
            {
                if (this._apiMethodType == ApiMethodTypes.QueryStringPara && !routUrl.Contains(WebConstnats.QUESTION_MARK))
                {
                    routUrl = $"{routTemplate}{WebConstnats.QUESTION_MARK}{routUrl}";
                    templateUrl = $"{routTemplate}{WebConstnats.QUESTION_MARK}{methodAttribute.Template}";
                }
                else
                {
                    routUrl = PathEx.Combine(PathType.Web, routTemplate, routUrl);
                    templateUrl = PathEx.Combine(PathType.Web, routTemplate, methodAttribute.Template);
                    //routUrl = $"{basesUrl}{Path.AltDirectorySeparatorChar}{routUrl}";
                    //templateUrl = $"{basesUrl}{Path.AltDirectorySeparatorChar}{methodAttribute.Template}";
                }
            }

            this._routUrl = routUrl;
            this._templateUrl = templateUrl;

            if (this._apiMethodType != ApiMethodTypes.FixUrl)
            {
                this._tempParaApiFixUrlPrefix = routUrl.Substring(0, routUrl.IndexOf('{'));
            }
        }



        private void UpdateTemplate(MethodInfo methodInfo, HttpMethodAbsAttribute methodAttribute, ReadOnlyCollection<ApiParameterInfo> apiParameterInfos)
        {
            if (apiParameterInfos == null ||
                apiParameterInfos.Count == 0 ||
                !string.IsNullOrWhiteSpace(methodAttribute.Template))
            {
                return;
            }

            if (!apiParameterInfos.Any(t => { return t.TemplateParameterType != ApiParameterValueSourceTypes.FromBody && t.TemplateParameterType != ApiParameterValueSourceTypes.ActionContext; }))
            {
                //没有除body和ContextData外的参数,不更新模板
                return;
            }


            StringBuilder sb = new StringBuilder();
            sb.Append(methodInfo.Name);
            sb.Append('?');
            bool appendAndSigin = false;

            foreach (var apiParameterInfo in apiParameterInfos)
            {
                if (apiParameterInfo.TemplateParameterType == ApiParameterValueSourceTypes.FromBody ||
                    apiParameterInfo.TemplateParameterType == ApiParameterValueSourceTypes.ActionContext)
                {
                    continue;
                }

                if (appendAndSigin)
                {
                    sb.Append('&');
                }

                sb.Append(apiParameterInfo.ParameterInfo.Name);
                sb.Append("={");
                sb.Append(apiParameterInfo.ParameterInfo.Name);
                sb.Append('}');
                appendAndSigin = true;
            }

            string template = sb.ToString();
            methodAttribute.UpdateTemplate(template);
        }

        private string GenerateRoutUrl(ApiMethodTypes urlType, MethodInfo methodInfo, HttpMethodAbsAttribute methodAttribute, ReadOnlyCollection<ApiParameterInfo> apiParameterInfos,
            out ApiTemplatePara urlTemplateApiTemplatePara, out ApiTemplatePara queryStringTemplateApiTemplatePara)
        {
            urlTemplateApiTemplatePara = null;
            queryStringTemplateApiTemplatePara = null;

            string template = methodAttribute.Template;
            if (urlType == ApiMethodTypes.FixUrl)
            {
                return template;
            }

            Dictionary<string, ApiParameterInfo> apiParameterInfoDic = apiParameterInfos.ToDictionary(t => { return t.ParameterInfo.Name; });
            string routUrl;

            switch (urlType)
            {
                case ApiMethodTypes.FixUrl:
                    throw new ApplicationException(urlType.ToString());
                case ApiMethodTypes.QueryStringPara:
                    //QueryString参数模板 eg:test?min={timestampMin}&max={timestampMax}
                    routUrl = this.GenerateQueryStringTemplateRoutUrl(apiParameterInfoDic, methodInfo, template, out queryStringTemplateApiTemplatePara);
                    break;
                case ApiMethodTypes.UrlPara:
                    //url参数模板eg:{z}/{x}/{y}.png 或 abc{z}/gg{x}mm/{y}.png
                    routUrl = this.GenerateUrlTemplateRoutUrl(apiParameterInfoDic, methodInfo, template, out urlTemplateApiTemplatePara);
                    break;
                case ApiMethodTypes.Mix:
                    //混合参数模板 eg:{z}/{x}/{y}.png?id=123&ts=456
                    routUrl = this.GenerateMixTemplateRoutUrl(apiParameterInfoDic, methodInfo, template, out urlTemplateApiTemplatePara, out queryStringTemplateApiTemplatePara);
                    break;
                default:
                    throw new NotImplementedException(urlType.ToString());
            }

            return routUrl;
        }

        private string GenerateMixTemplateRoutUrl(Dictionary<string, ApiParameterInfo> apiParameterInfoDic,
            MethodInfo methodInfo, string template, out ApiTemplatePara urlTemplateApiTemplatePara, out ApiTemplatePara queryStringTemplateApiTemplatePara)
        {
            int questionMarkIndex = template.IndexOf('?');
            string urlParaTempate = template.Substring(0, questionMarkIndex);
            string queryStringParaTemplate = template.Substring(questionMarkIndex);

            StringBuilder sbRoutUrl = new StringBuilder();
            int paraIndex = 0;
            int urlTemplateParaCount = 0;

            List<UrlSegment> urlSegmentList;
            this.PrimitiveGenerateUrlTemplateRoutUrl(apiParameterInfoDic, methodInfo, urlParaTempate, sbRoutUrl, ref paraIndex, out urlSegmentList);
            if (urlSegmentList != null && urlSegmentList.Count > 0)
            {
                urlTemplateParaCount = paraIndex;
                urlTemplateApiTemplatePara = new ApiTemplatePara(urlTemplateParaCount, urlSegmentList);
            }
            else
            {
                urlTemplateApiTemplatePara = null;
            }

            //添加?号连接符号
            sbRoutUrl.Append(WebConstnats.QUESTION_MARK);

            List<UrlSegment> queryStringSegmentList;
            this.PrimitiveGenerateQueryStringTemplateRoutUrl(apiParameterInfoDic, methodInfo, queryStringParaTemplate, sbRoutUrl, ref paraIndex, out queryStringSegmentList);
            if (queryStringSegmentList != null && queryStringSegmentList.Count > 0)
            {
                queryStringTemplateApiTemplatePara = new ApiTemplatePara(paraIndex - urlTemplateParaCount, queryStringSegmentList);
            }
            else
            {
                queryStringTemplateApiTemplatePara = null;
            }

            return sbRoutUrl.ToString();
        }





        private string GenerateUrlTemplateRoutUrl(Dictionary<string, ApiParameterInfo> apiParameterInfoDic,
            MethodInfo methodInfo, string urlParaTempate, out ApiTemplatePara urlTemplateApiTemplatePara)
        {
            StringBuilder sbRoutUrl = new StringBuilder();
            int paraIndex = 0;

            List<UrlSegment> urlSegmentList;
            this.PrimitiveGenerateUrlTemplateRoutUrl(apiParameterInfoDic, methodInfo, urlParaTempate, sbRoutUrl, ref paraIndex, out urlSegmentList);
            if (urlSegmentList != null && urlSegmentList.Count > 0)
            {
                urlTemplateApiTemplatePara = new ApiTemplatePara(paraIndex, urlSegmentList);
            }
            else
            {
                urlTemplateApiTemplatePara = null;
            }

            return sbRoutUrl.ToString();
        }

        private void PrimitiveGenerateUrlTemplateRoutUrl(Dictionary<string, ApiParameterInfo> apiParameterInfoDic, MethodInfo methodInfo,
            string urlParaTempate, StringBuilder sbRoutUrl, ref int paraIndex, out List<UrlSegment> urlSegmentList)
        {
            urlSegmentList = new List<UrlSegment>();
            string[] urlSliceArr = urlParaTempate.Split(WebConstnats.PATH_SEPARATOR_ARR, StringSplitOptions.RemoveEmptyEntries);
            int leftBraceIndex, rightBraceIndex;
            string templateParaName, paraPrefix, paraSuffix;
            ApiParameterInfo apiParameterInfo;

            foreach (var urlSlice in urlSliceArr)
            {
                if (sbRoutUrl.Length > 0)
                {
                    sbRoutUrl.Append('/');
                }

                if (!urlSlice.Contains('{'))
                {
                    sbRoutUrl.Append(urlSlice);
                    urlSegmentList.Add(new UrlSegment(urlSlice));
                    continue;
                }

                leftBraceIndex = -1;
                rightBraceIndex = -1;
                for (int i = 0; i < urlSlice.Length; i++)
                {
                    if (urlSlice[i] == '{')
                    {
                        if (leftBraceIndex >= 0)
                        {
                            throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的模板无效,以/分隔的url中,每两个/之间的部分最多允许一个模板参数");
                        }
                        leftBraceIndex = i;
                    }
                    else if (urlSlice[i] == '}')
                    {
                        if (rightBraceIndex >= 0)
                        {
                            throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的模板无效,以/分隔的url中,每两个/之间的部分最多允许一个模板参数");
                        }
                        rightBraceIndex = i;
                    }
                }

                if (leftBraceIndex >= 0)
                {
                    paraPrefix = urlSlice.Substring(0, leftBraceIndex);
                }
                else
                {
                    paraPrefix = null;
                }

                if (rightBraceIndex > 0)
                {
                    paraSuffix = urlSlice.Substring(rightBraceIndex + 1);
                }
                else
                {
                    paraSuffix = null;
                }


                if (leftBraceIndex < 0)
                {
                    leftBraceIndex = 0;
                }

                if (rightBraceIndex < 0)
                {
                    rightBraceIndex = urlSlice.Length - 1;
                }

                templateParaName = urlSlice.Substring(leftBraceIndex + 1, rightBraceIndex - leftBraceIndex - 1);
                if (!apiParameterInfoDic.TryGetValue(templateParaName, out apiParameterInfo))
                {
                    throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的模板参数\"{templateParaName}\"找不着与之对应的方法参数");
                }
                apiParameterInfo.UpdateApiParameterValueSourceType(ApiParameterValueSourceTypes.FromUrl, templateParaName);
                urlSegmentList.Add(new UrlSegment(templateParaName, paraPrefix, paraSuffix, apiParameterInfo));

                sbRoutUrl.Append(paraPrefix);
                sbRoutUrl.Append('{');
                sbRoutUrl.Append(paraIndex);
                sbRoutUrl.Append('}');
                sbRoutUrl.Append(paraSuffix);

                paraIndex++;
            }
        }






        private string GenerateQueryStringTemplateRoutUrl(Dictionary<string, ApiParameterInfo> apiParameterInfoDic,
            MethodInfo methodInfo, string queryStringParaTemplate, out ApiTemplatePara queryStringTemplateApiTemplatePara)
        {
            StringBuilder sbRoutUrl = new StringBuilder();
            int paraIndex = 0;
            List<UrlSegment> queryStringSegmentList;
            this.PrimitiveGenerateQueryStringTemplateRoutUrl(apiParameterInfoDic, methodInfo, queryStringParaTemplate, sbRoutUrl, ref paraIndex, out queryStringSegmentList);
            if (queryStringSegmentList != null && queryStringSegmentList.Count > 0)
            {
                queryStringTemplateApiTemplatePara = new ApiTemplatePara(paraIndex, queryStringSegmentList);
            }
            else
            {
                queryStringTemplateApiTemplatePara = null;
            }

            return sbRoutUrl.ToString();
        }

        private void PrimitiveGenerateQueryStringTemplateRoutUrl(Dictionary<string, ApiParameterInfo> apiParameterInfoDic,
            MethodInfo methodInfo, string queryStringParaTemplate, StringBuilder sbRoutUrl, ref int paraIndex, out List<UrlSegment> urlSegmentList)
        {
            urlSegmentList = new List<UrlSegment>();

            //test?min={timestampMin}&max={timestampMax}
            //id={id}  => ?id={id}
            if (!queryStringParaTemplate.Contains(WebConstnats.QUESTION_MARK))
            {
                queryStringParaTemplate = WebConstnats.QUESTION_MARK + queryStringParaTemplate;
            }

            int noParaNameBeginIndex = -1, paraNameBeginIndex = -1;
            string noParaStr, templateParaName;
            ApiParameterInfo apiParameterInfo;
            string urlParaName = null;
            int urlParaNameBeginIndex = -1;
            int queryStringParaCount = 0;

            for (int i = 0; i < queryStringParaTemplate.Length; i++)
            {
                if (queryStringParaTemplate[i] == '?' || queryStringParaTemplate[i] == '&')
                {
                    urlParaNameBeginIndex = i;
                    continue;
                }
                else if (queryStringParaTemplate[i] == '=')
                {
                    if (urlParaNameBeginIndex >= 0)
                    {
                        urlParaName = queryStringParaTemplate.Substring(urlParaNameBeginIndex + 1, i - urlParaNameBeginIndex - 1);
                        urlParaNameBeginIndex = -1;
                    }
                    continue;
                }

                if (paraNameBeginIndex >= 0)
                {
                    if (queryStringParaTemplate[i] != '}')
                    {
                        continue;
                    }

                    templateParaName = queryStringParaTemplate.Substring(paraNameBeginIndex + 1, i - paraNameBeginIndex - 1);
                    if (!apiParameterInfoDic.TryGetValue(templateParaName, out apiParameterInfo))
                    {
                        throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的模板参数\"{templateParaName}\"找不着与之对应的方法参数");
                    }
                    apiParameterInfo.UpdateApiParameterValueSourceType(ApiParameterValueSourceTypes.FromQueryString, templateParaName);

                    if (string.IsNullOrWhiteSpace(urlParaName))
                    {
                        throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中模板\"{queryStringParaTemplate}\"无效");
                    }

                    urlSegmentList.Add(new UrlSegment(urlParaName, apiParameterInfo));
                    queryStringParaCount++;

                    sbRoutUrl.Append('{');
                    sbRoutUrl.Append(paraIndex);
                    sbRoutUrl.Append('}');

                    paraIndex++;
                    paraNameBeginIndex = -1;
                    urlParaName = null;
                }
                else
                {
                    if (queryStringParaTemplate[i] == '{')
                    {
                        paraNameBeginIndex = i;

                        if (noParaNameBeginIndex >= 0)
                        {
                            noParaStr = queryStringParaTemplate.Substring(noParaNameBeginIndex, i - noParaNameBeginIndex);
                            if (queryStringParaCount > 0)
                            {
                                sbRoutUrl.Append(WebConstnats.AND_MARK);
                            }
                            sbRoutUrl.Append(noParaStr);
                            noParaNameBeginIndex = -1;
                        }
                    }
                    else
                    {
                        if (noParaNameBeginIndex < 0)
                        {
                            noParaNameBeginIndex = i;
                        }

                        continue;
                    }
                }
            }
        }




        private ReadOnlyCollection<ApiParameterInfo> GetApiMethodParameterInfo(MethodInfo methodInfo)
        {
            ParameterInfo[] parameters = methodInfo.GetParameters();
            var apiParameterInfos = new List<ApiParameterInfo>(parameters.Length);

            FromBodyAttribute fromBodyAttribute;
            bool hasFromBodyParameter = false;
            bool hasContextDataParameter = false;
            ApiParameterValueSourceTypes parameterSourceType;

            foreach (ParameterInfo parameter in parameters)
            {
#if NET4_0
                fromBodyAttribute = TypeEx.GetCustomAttribute<FromBodyAttribute>(parameter, true);
#else
                fromBodyAttribute = parameter.GetCustomAttribute<FromBodyAttribute>();
#endif

                if (fromBodyAttribute != null)
                {
                    if (hasFromBodyParameter)
                    {
                        throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的{nameof(FromBodyAttribute)}参数不能多于一个");
                    }

                    hasFromBodyParameter = true;
                    parameterSourceType = ApiParameterValueSourceTypes.FromBody;
                }
                else
                {
                    if (parameter.ParameterType == typeof(HttpActionContext))
                    {
                        if (hasContextDataParameter)
                        {
                            throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的{nameof(HttpActionContext)}参数不能多于一个");
                        }

                        hasContextDataParameter = true;
                        parameterSourceType = ApiParameterValueSourceTypes.ActionContext;
                    }
                    else if (TypeEx.GetTypeTypeCategory(parameter.ParameterType) == TypeCategorys.Object)
                    {
                        if (hasFromBodyParameter)
                        {
                            throw new ArgumentException($"Api方法{methodInfo.DeclaringType.FullName}.{methodInfo.Name}中的{nameof(FromBodyAttribute)}参数不能多于一个");
                        }

                        hasFromBodyParameter = true;
                        parameterSourceType = ApiParameterValueSourceTypes.FromBody;
                    }
                    else
                    {
                        parameterSourceType = ApiParameterValueSourceTypes.None;
                    }
                }

                apiParameterInfos.Add(new ApiParameterInfo(parameterSourceType, parameter));
            }

            return new ReadOnlyCollection<ApiParameterInfo>(apiParameterInfos);
        }

        private void TestGetApiMethodTypeByTemplate()
        {
            var type1 = GetApiMethodTypeByTemplate(@"fix", null);
            var type12 = GetApiMethodTypeByTemplate(null, null);
            var type13 = GetApiMethodTypeByTemplate(string.Empty, null);
            var type14 = GetApiMethodTypeByTemplate(@"   ", null);
            var type15 = GetApiMethodTypeByTemplate(@"id={id}", null);

            var type2 = GetApiMethodTypeByTemplate(@"qsp?min={timestampMin}&max={timestampMax}", null);
            var type3 = GetApiMethodTypeByTemplate(@"url/{z}/gg{x}mm/kk/{y}.png", null);
            var type4 = GetApiMethodTypeByTemplate(@"mid/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}", null);
        }

        /// <summary>
        /// 获取模板url对应的api方法类型
        /// </summary>
        /// <param name="template">模板</param>
        /// <param name="apiParameterInfos">api参数信息集合</param>
        /// <returns>WebUrlType</returns>
        private ApiMethodTypes GetApiMethodTypeByTemplate(string template, ReadOnlyCollection<ApiParameterInfo> apiParameterInfos)
        {
            /******************************************************
             * FixUrl               http://api/v1/fix       (固定模板或模板为空皆为固定url)
             * QueryStringPara      http://192.168.10.96:23018/testApi/qsp?min={timestampMin}&max={timestampMax}
             * UrlPara              http://192.168.10.96:23018/testApi/url/{z}/gg{x}mm/kk/{y}.png
             * Mix                  http://192.168.10.96:23018/testApi/mix/{z}/gg{x}mm/kk/{y}.png?min={timestampMin}&max={timestampMax}
             ******************************************************/

            if (string.IsNullOrWhiteSpace(template))
            {
                if (apiParameterInfos != null &&
                    apiParameterInfos.Any(t => { return t.TemplateParameterType != ApiParameterValueSourceTypes.FromBody && t.TemplateParameterType != ApiParameterValueSourceTypes.ActionContext; }))
                {
                    return ApiMethodTypes.QueryStringPara;
                }
                else
                {
                    return ApiMethodTypes.FixUrl;
                }
            }


            int braceIndex;
            int questionMarkIndex = template.IndexOf('?');

            if (questionMarkIndex >= 0)
            {
                //模板中有?
                string url = template.Substring(0, questionMarkIndex);
                braceIndex = url.IndexOf('{');
                if (braceIndex >= 0)
                {
                    return ApiMethodTypes.Mix;
                }
                else
                {
                    return ApiMethodTypes.QueryStringPara;
                }
            }
            else
            {
                //模板中无?

                int equalsMarkIndex = template.IndexOf('=');
                if (equalsMarkIndex >= 0)
                {
                    //模板中无?有=  eg: id={id} 或 test/id={id} 或 test/{year}/id={id}

                    for (int i = equalsMarkIndex; i >= 0; i--)
                    {
                        if (template[i] == '}')
                        {
                            throw new ArgumentException($"Api方法模板\"{template}\"不合法");
                            //return ApiMethodTypes.Mix;
                        }
                    }

                    return ApiMethodTypes.QueryStringPara;
                }
                else
                {
                    //模板中无?和= 
                    braceIndex = template.IndexOf('{');
                    if (braceIndex >= 0)
                    {
                        return ApiMethodTypes.UrlPara;
                    }
                    else
                    {
                        return ApiMethodTypes.FixUrl;
                    }
                }
            }
        }


        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns>String</returns>
        public override string ToString()
        {
            return this._methodAttribute.Method;
        }
    }
}
